package com.zl.ots.wrapper;

import com.alicloud.openservices.tablestore.model.search.SearchQuery;
import com.alicloud.openservices.tablestore.model.search.query.*;
import com.alicloud.openservices.tablestore.model.search.sort.FieldSort;
import com.alicloud.openservices.tablestore.model.search.sort.Sort;
import com.alicloud.openservices.tablestore.model.search.sort.SortOrder;
import com.zl.ots.OtsClient;
import com.zl.ots.utils.NamingConverterUtil;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * 抽象wrapper
 */
public class AbstractWrapper<T> {

    /**
     * 排序
     */
    protected List<OrderBy> orderByList = new ArrayList<>();

    /**
     * 临时过滤条件
     */
    protected  List<TempQuery> tempQuerys = new ArrayList<>();



    /**
     * 转换为ots searchQuery
     */
    public SearchQuery build() {
        SearchQuery searchQuery = new SearchQuery();
        BoolQuery boolQuery = new BoolQuery();
        List<Query> queryList = new ArrayList<>();

        for(TempQuery tempQuery : tempQuerys){
            Query query = toQuery(tempQuery);
            if(!ObjectUtils.isEmpty(query)) {
                queryList.add(query);
            }
        }
        boolQuery.setMustQueries(queryList);
        //排序
        searchQuery.setQuery(boolQuery);
        if(!ObjectUtils.isEmpty(orderByList)){
            List<Sort.Sorter> sorts = new ArrayList<>();
            for(OrderBy orderBy : orderByList){
                String property = NamingConverterUtil.camelToSnake(orderBy.getProperty());
                FieldSort fieldSort = new FieldSort(property, orderBy.isDesc() ? SortOrder.DESC : SortOrder.ASC);
                sorts.add(fieldSort);
            }
            Sort sort = new Sort(sorts);
            searchQuery.setSort(sort);
        }
        return searchQuery;
    }

    @SuppressWarnings("unchecked")
    public Query toQuery(TempQuery query) {
        Object value = query.getValue();
        if(value instanceof String){
            Assert.isTrue(((String) value).length() <= 32,"搜索字符串长度过长!");
        }
        switch (query.getOperator()) {
            case EQ:
                if(ObjectUtils.isEmpty(value)){
                    return null;
                }
                TermQuery eqQuery = new TermQuery(); //设置查询类型为TermQuery。
                eqQuery.setFieldName(query.getFieldName()); //设置要匹配的字段。
                eqQuery.setTerm(OtsClient.getColumnValue(query.getValue()));
                return eqQuery;
            case NE:
                if(ObjectUtils.isEmpty(value)){
                    return null;
                }
                TermQuery neQuery = new TermQuery(); //设置查询类型为TermQuery。
                neQuery.setFieldName(query.getFieldName()); //设置要匹配的字段。
                neQuery.setTerm(OtsClient.getColumnValue(query.getValue()));
                BoolQuery neBoolQuery = new BoolQuery();
                neBoolQuery.setMustNotQueries(Collections.singletonList(neQuery));
                return neBoolQuery;
            case GE:
                if(ObjectUtils.isEmpty(value)){
                    return null;
                }
                RangeQuery geQuery = new RangeQuery(); //设置查询类型为RangeQuery。
                geQuery.setFieldName(query.getFieldName());  //设置要匹配的字段。
                geQuery.greaterThanOrEqual(OtsClient.getColumnValue(query.getValue()));
                return geQuery;
            case GT:
                if(ObjectUtils.isEmpty(value)){
                    return null;
                }
                RangeQuery gtQuery = new RangeQuery(); //设置查询类型为RangeQuery。
                gtQuery.setFieldName(query.getFieldName());  //设置要匹配的字段。
                gtQuery.greaterThan(OtsClient.getColumnValue(query.getValue()));
                return gtQuery;
            case LE:
                if(ObjectUtils.isEmpty(value)){
                    return null;
                }
                RangeQuery leQuery = new RangeQuery(); //设置查询类型为RangeQuery。
                leQuery.setFieldName(query.getFieldName());  //设置要匹配的字段。
                leQuery.lessThanOrEqual(OtsClient.getColumnValue(query.getValue()));
                return leQuery;
            case LT:
                if(ObjectUtils.isEmpty(value)){
                    return null;
                }
                RangeQuery ltQuery = new RangeQuery(); //设置查询类型为RangeQuery。
                ltQuery.setFieldName(query.getFieldName());  //设置要匹配的字段。
                ltQuery.lessThan(OtsClient.getColumnValue(query.getValue()));
                return ltQuery;
            case IN:
                if(ObjectUtils.isEmpty(value)){
                    return null;
                }
                List<Object> inObjects = new ArrayList<>();
                if(value instanceof List){
                    inObjects = (List<Object>)value;
                }else {
                   inObjects = Arrays.asList((Object[]) value);
                }
                TermsQuery inQuery = new TermsQuery(); //设置查询类型为TermsQuery。
                inQuery.setFieldName(query.getFieldName()); //设置要匹配的字段。
                for(Object o : inObjects){
                    inQuery.addTerm(OtsClient.getColumnValue(o));
                }
                BoolQuery boolQuery = new BoolQuery();
                boolQuery.setMustNotQueries(Collections.singletonList(inQuery));
                return inQuery;
            case NOTIN:
                if(ObjectUtils.isEmpty(value)){
                    return null;
                }
                List<Object> notInObjects = new ArrayList<>();
                if(value instanceof List){
                    notInObjects = (List<Object>)value;
                }else {
                    notInObjects = Arrays.asList((Object[]) value);
                }
                TermsQuery termsQuery = new TermsQuery(); //设置查询类型为TermsQuery。
                termsQuery.setFieldName(query.getFieldName()); //设置要匹配的字段。
                for(Object o : notInObjects){
                    termsQuery.addTerm(OtsClient.getColumnValue(o));
                }
                BoolQuery notInBoolQuery = new BoolQuery();
                notInBoolQuery.setMustNotQueries(Collections.singletonList(notInBoolQuery));
                return notInBoolQuery;
            case LIKE:
                if(ObjectUtils.isEmpty(value)){
                    return null;
                }
                WildcardQuery matchQuery = new WildcardQuery(); //设置查询类型为MatchQuery。
                matchQuery.setFieldName(query.getFieldName()); //设置要匹配的列。
                matchQuery.setValue("*"+String.valueOf(query.getValue())+"*"); //设置要匹配的值。
                return matchQuery;
            case ISNULL:
                ExistsQuery isNullQuery = new ExistsQuery(); //设置查询类型为ExistsQuery。
                isNullQuery.setFieldName(query.getFieldName());
                BoolQuery isNullBoolQuery = new BoolQuery();
                isNullBoolQuery.setMustNotQueries(Collections.singletonList(isNullQuery));
                return isNullBoolQuery;
            case NOTNULL:
                ExistsQuery notNullQuery = new ExistsQuery(); //设置查询类型为ExistsQuery。
                notNullQuery.setFieldName(query.getFieldName());
                return notNullQuery;
            case PREFIX:
                if(ObjectUtils.isEmpty(value)){
                    return null;
                }
                PrefixQuery prefixQuery = new PrefixQuery(); //设置查询类型为PrefixQuery。
                prefixQuery.setFieldName(query.getFieldName());
                prefixQuery.setPrefix(String.valueOf(query.getValue()));
                return prefixQuery;
            case PREFIXS:
                if(ObjectUtils.isEmpty(value)){
                    return null;
                }
                List<Object> prefixObjs = new ArrayList<>();
                if(value instanceof List){
                    prefixObjs = (List<Object>)value;
                }else {
                    prefixObjs = Arrays.asList((Object[]) value);
                }
                List<Query> prefixQueryList = new ArrayList<>();
                for(Object obj : prefixObjs){
                    PrefixQuery childPrefixQuery = new PrefixQuery(); //设置查询类型为PrefixQuery。
                    childPrefixQuery.setFieldName(query.getFieldName());
                    childPrefixQuery.setPrefix(String.valueOf(obj));
                    prefixQueryList.add(childPrefixQuery);
                }
                BoolQuery orPrefixQuery = new BoolQuery();
                orPrefixQuery.setShouldQueries(prefixQueryList);
                return orPrefixQuery;
            case JSON:
                if(ObjectUtils.isEmpty(value)){
                    return null;
                }
                //此处json对象索引类型是字符串，随意需要进行字符串匹配 采用通配符方式进行匹配 *fifteenMinutes???1*
                String relValue = "*"+query.getChildFieldPath()+"???"+value+"*";
//                NestedQuery nestedQuery = new NestedQuery(); //设置查询类型为NestedQuery。
//                nestedQuery.setPath(query.getChildFieldPath()); //设置嵌套类型列的路径。
//                TermQuery termQuery = new TermQuery(); //构造NestedQuery的子查询。
//                termQuery.setFieldName(query.getFieldName()); //设置列名，注意带有嵌套类型列的路径。
//                termQuery.setTerm(OtsUtils.getColumnValue(query.getValue())); //设置要查询的值。
//                nestedQuery.setQuery(termQuery);
//                nestedQuery.setScoreMode(ScoreMode.None);
//                return nestedQuery;
                WildcardQuery jsonMatchQuery = new WildcardQuery(); //设置查询类型为MatchQuery。
                jsonMatchQuery.setFieldName(query.getFieldName()); //设置要匹配的列。
                jsonMatchQuery.setValue(relValue); //设置要匹配的值。
                return jsonMatchQuery;
            case OR:
                //或者
                List<TempQuery> orQuerys = query.getOrQuerys();
                if(ObjectUtils.isEmpty(orQuerys)){
                    return null;
                }
                BoolQuery orQuery = new BoolQuery();
                List<Query> orQueryList = new ArrayList<>();
                for(TempQuery tempQuery : orQuerys){
                    Query orChildQuery = toQuery(tempQuery);
                    if(!ObjectUtils.isEmpty(orChildQuery)) {
                        orQueryList.add(orChildQuery);
                    }
                }
                orQuery.setShouldQueries(orQueryList);
                return orQuery;
            case AND:
                //或者
                List<TempQuery> andQuerys = query.getAndQuerys();
                if(ObjectUtils.isEmpty(andQuerys)){
                    return null;
                }
                BoolQuery andQuery = new BoolQuery();
                List<Query> andQueryList = new ArrayList<>();
                for(TempQuery tempQuery : andQuerys){
                    Query andChildQuery = toQuery(tempQuery);
                    if(!ObjectUtils.isEmpty(andChildQuery)) {
                        andQueryList.add(andChildQuery);
                    }
                }
                andQuery.setMustQueries(andQueryList);
                return andQuery;
            default:
        }
        return null;
    }
}

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
class OrderBy {
    /**
     * 属性
     */
    private String property;
    /**
     * 是否是desc
     */
    private boolean isDesc;
}

/**
 * 临时断言
 */
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
class TempQuery {
    /**
     * 字段名 表字段名
     */
    private String fieldName;

    /**
     * json对象查询 如果只有一级 直接返回属性名，比如 userName
     * 如果是多级 可以用点分割，比如返回 user.userName
     */
    private String childFieldPath;

    /**
     * 操作符
     */
    private Operator operator;

    /**
     * 值
     */
    private Object value;

    /**
     * 或者判断
     */
    private List<TempQuery> orQuerys = new ArrayList<>();


    /**
     * 追加并且判断
     */
    private List<TempQuery> andQuerys = new ArrayList<>();
}

enum Operator {
    //
    EQ, LIKE, NE, GE, GT, LE, LT, IN, NOTIN,ISNULL,NOTNULL,PREFIX,PREFIXS,JSON,OR,AND;
}
